/*
 * Copyright 2012 Gregor Schauer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package at.schauer.gregor.vienna.datastore;

import at.schauer.gregor.vienna.context.ViennaContext;
import at.schauer.gregor.vienna.context.ViennaContextAware;
import at.schauer.gregor.vienna.metadata.MetadataProvider;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Gregor Schauer
 */
public class MemoryDataStore<T> implements DataStore<T>, ViennaContextAware {
	protected final Map<Class<?>, Map<Object, ? extends T>> cache = new HashMap<Class<?>, Map<Object, ? extends T>>();
	protected ViennaContext ctx;

	@SuppressWarnings("unchecked")
	public <E extends T> Map<Object, E> getCache(Class<E> type) {
		Map<Object, E> map = (Map<Object, E>) cache.get(type);
		if (map == null) {
			synchronized (cache) {
				map = (Map<Object, E>) cache.get(type);
				if (map == null) {
					map = new HashMap<Object, E>();
					cache.put(type, map);
				}
			}
		}
		return map;
	}

	@Override
	public <E extends T> E load(Class<E> type, Object identifier) {
		return getCache(type).get(identifier);
	}

	@Override
	@SuppressWarnings("unchecked")
	public Object save(@Nonnull T obj) {
		Class<T> type = (Class<T>) obj.getClass();
		MetadataProvider<T> metadataProvider = ctx.getMetadataProvider(type);
		Object identifier = metadataProvider.getIdentifier(obj);
		getCache(type).put(identifier, obj);
		return identifier;
	}

	@Override
	@SuppressWarnings("unchecked")
	public void delete(@Nonnull T obj) {
		Class<T> type = (Class<T>) obj.getClass();
		MetadataProvider<T> metadataProvider = ctx.getMetadataProvider(type);
		Object identifier = metadataProvider.getIdentifier(obj);
		getCache(type).remove(identifier);
	}

	@Override
	public <E extends T> Collection<E> list(Class<E> type) {
		return new ArrayList<E>(getCache(type).values());
	}

	public void clear() {
		cache.clear();
	}

	@Override
	public void setViennaContext(@Nonnull ViennaContext viennaContext) {
		this.ctx = viennaContext;
	}
}
